﻿using System;
using System.Collections.Generic;
using System.Text;

namespace VsTortoiseSVN
{
    /// <summary>
    /// TortoiseProc is a helper class to ease execution of TortoiseSVN commands.
    /// </summary>
    public static class TortoiseProc
    {
        private static class Revision
        {
            public const int Head = -1;
            public const int Base = -2;
            public const int WorkingCopy = -3;
        }
     
        public static void Properties(string path)
        {
            Exec("/command:properties", path);
        }

        public static void Properties(ICollection<string> paths)
        {
            Exec("/command:properties", paths);
        }

        public static void Add(string path)
        {
            Exec("/command:add", path);
        }

        public static void Add(ICollection<string> paths)
        {
            Exec("/command:add", paths);          
        }

        public static void Cleanup(ICollection<string> paths)
        {
            Exec("/command:cleanup", paths);
        }

        public static void Commit(string path)
        {
            Exec("/command:commit", path);
        }

        public static void Commit(ICollection<string> paths)
        {
            Exec("/command:commit", paths);
        }
        
        public static void Diff(string path)
        {
            Exec("/command:diff", path);
        }
        
        public static void Diff(string path, int line)
        {
            string args = string.Format("/command:diff /line:{0}", line);
            Exec(args, path);
        }
        
        public static void Diff(ICollection<string> paths)
        {
            Exec("/command:diff", paths);
        }
        
        public static void DiffWithPreviousVersion(string path)
        {
            SharpSvn.SvnStatusEventArgs status;
            if (SvnHelper.FileStatus(path, out status))
            {
                long startrev = status.WorkingCopyInfo.LastChangeRevision - 1;
                if (startrev > 0)
                {
                    string args = string.Format("/command:diff /startrev:{0} /endrev:{1}", Revision.WorkingCopy, startrev);
                    Exec(args, path);
                }
            }
        }

        public static void DiffWithPreviousVersion(string path, int line)
        {
            SharpSvn.SvnStatusEventArgs status;
            if (SvnHelper.FileStatus(path, out status))
            {
                long startrev = status.WorkingCopyInfo.LastChangeRevision - 1;
                if (startrev > 0)
                {
                    string args = string.Format("/command:diff /line:{0} /startrev:{1} /endrev:{2}", line, Revision.WorkingCopy, startrev);
                    Exec(args, path);
                }
            }
        }

        public static void Lock(ICollection<string> paths)
        {
            Exec("/command:lock", paths);
        }

        public static void Unlock(ICollection<string> paths)
        {
            Exec("/command:unlock", paths);
        }

        public static void CompareWithBase(ICollection<string> paths)
        {
            foreach (string path in paths)
            {
                // http://tortoisesvn.tigris.org/ds/viewMessage.do?dsForumId=4061&dsMessageId=2448492
                Exec("/command:diff", path);
            }
        }

        public static void Blame(string path)
        {
            Exec("/command:blame", path);
        }

        public static void Blame(string path, int line)
        {
            string args = string.Format("/command:blame /line:{0}", line);
            Exec(args, path);
        }

        public static void EditConflicts(string path)
        {
            Exec("/command:conflicteditor", path);
        }

        public static void Resolve(string path)
        {
            Exec("/command:resolve", path);
        }

        public static void Resolve(ICollection<string> paths)
        {
            Exec("/command:resolve", paths);
        }

        public static void Revert(string path)
        {
            Exec("/command:revert", path);
        }

        public static void Revert(ICollection<string> paths)
        {
            Exec("/command:revert", paths);
        }

        public static void ShowLog(string path)
        {
            Exec("/command:log", path);
        }

        public static void Update(string path)
        {
            Exec("/command:update", path);
        }

        public static void Update(ICollection<string> paths)
        {
            Exec("/command:update", paths);
        }

        /// <summary>
        /// Opens the TortoiseSVN "Update to Revision" dialog where the user
        /// can pick the revision number.
        /// </summary>
        public static void UpdateToRevision(string path)
        {
            Exec("/command:update /rev", path);
        }

        /// <summary>
        /// Opens the TortoiseSVN "Update to Revision" dialog where the user
        /// can pick the revision number.
        /// </summary>
        public static void UpdateToRevision(ICollection<string> paths)
        {
            Exec("/command:update /rev", paths);
        }

        /// <summary>
        /// Opens the TortoiseSVN Repository Browser dialog, pointing to the URL of the working copy given in path.
        /// </summary>
        /// <param name="path"></param>
        public static void RepoBrowser(string path)
        {
            Exec("/command:repobrowser", path);
        }


        /// <summary>
        /// Execute TortoiseSVN with the given options string.
        /// </summary>
        private static void Exec(string options, string path)
        {
            if(!string.IsNullOrEmpty(path))
                options += " /path:\"" + path + "\"";

            Win32.CreateProcess("TortoiseProc.exe", options);
        }

        /// <summary>
        /// Execute TortoiseSVN with the given options string.
        /// </summary>
        private static void Exec(string options, ICollection<string> paths)
        {
            if(paths.Count > 0)
                options += BuildPathParam(paths);

            Win32.CreateProcess("TortoiseProc.exe", options);
        }


        /// <summary>
        /// Builds the "path" parameter.
        /// TortoiseSVN expects paths delimited by a star symbol.
        /// Example:
        /// /path:"c:\folder\file.bin*c:\another folder\file.txt"
        /// </summary>
        private static string BuildPathParam(ICollection<string> paths)
        {
            List<string> mergedPaths = new List<string>(64);

            // Remove sub-directories
            PathHelper.RemoveSubDirectories(mergedPaths, paths);

            // Build the TortoiseSVN Update string
            string pathsList = string.Empty;
            for (int n = 0; n < mergedPaths.Count; ++n)
            {
                string path = mergedPaths[n];

                if (string.IsNullOrEmpty(pathsList))
                    pathsList += path;
                else
                    pathsList += "*" + path;
            }

            return " /path:\"" + pathsList + "\"";
        }
    }
}
